"""Pipeline配置管理

提供PPG处理Pipeline的配置管理功能，包括：
- 配置文件加载和保存
- 参数验证
- 默认配置管理

作者: PPG算法包开发团队
版本: 2.0.0
"""

import json
from pathlib import Path
from typing import Dict, Any, Optional, Union
from dataclasses import dataclass, field, asdict
import logging

# 可选的YAML支持
try:
    import yaml
    YAML_AVAILABLE = True
except ImportError:
    YAML_AVAILABLE = False


@dataclass
class PipelineConfig:
    """Pipeline配置类
    
    属性:
        name: 配置名称
        description: 配置描述
        sampling_rate: 采样率
        preprocessing: 预处理参数
        peak_detection: 峰值检测参数
        hrv_analysis: HRV分析参数
        quality_assessment: 质量评估参数
        output_options: 输出选项
    """
    name: str = "default"
    description: str = "默认PPG处理配置"
    sampling_rate: float = 25.0
    
    # 预处理参数
    preprocessing: Dict[str, Any] = field(default_factory=lambda: {
        "outlier_detection": {
            "enabled": True,
            "method": "median_filter",
            "window_size": 25,
            "threshold_percentile": 95
        },
        "smoothing": {
            "enabled": True,
            "method": "savgol",
            "window_length": 21,
            "polynomial_order": 3
        },
        "detrending": {
            "enabled": True,
            "method": "polynomial",
            "order": 2
        },
        "filtering": {
            "enabled": True,
            "method": "butterworth",
            "filter_type": "bandpass",
            "order": 4,
            "low_cutoff": 0.5,
            "high_cutoff": 3.0
        }
    })
    
    # 峰值检测参数
    peak_detection: Dict[str, Any] = field(default_factory=lambda: {
        "method": "adaptive",
        "height_percentile": 50,
        "distance_min": 8,
        "prominence_factor": 0.1,
        "width_min": 2,
        "heart_rate_range": [40, 150]
    })
    
    # HRV分析参数
    hrv_analysis: Dict[str, Any] = field(default_factory=lambda: {
        "enabled": True,
        "outlier_removal": {
            "enabled": True,
            "method": "zscore",
            "threshold": 3.0
        },
        "frequency_analysis": {
            "enabled": True,
            "resampling_rate": 4.0,
            # Welch功率谱密度估计参数（与脚本保持一致的可配置项）
            # 如果未设置nperseg，则默认使用重采样后序列长度的1/4
            "welch_nperseg": None,
            # 重叠比例(0.0-1.0)，例如0.5表示50%重叠
            "welch_overlap": 0.5,
            # 在计算PSD之前是否进行线性去趋势
            "detrend_before_psd": True,
            "vlf_band": [0.0033, 0.04],
            "lf_band": [0.04, 0.15],
            "hf_band": [0.15, 0.4]
        }
    })
    
    # 质量评估参数
    quality_assessment: Dict[str, Any] = field(default_factory=lambda: {
        "enabled": True,
        "segment_analysis": {
            "enabled": True,
            "window_size": 2.0,
            "quality_threshold_percentile": 15,
            "min_segment_duration": 3.0
        },
        "snr_analysis": {
            "enabled": True
        },
        "frequency_analysis": {
            "enabled": True,
            "hr_frequency_range": [0.8, 3.0]
        }
    })
    
    # 输出选项
    output_options: Dict[str, Any] = field(default_factory=lambda: {
        "include_processed_signal": True,
        "include_peaks": True,
        "include_heart_rates": True,
        "include_hrv": True,
        "include_quality": True,
        "include_segments": False,
        "verbose": False
    })
    
    def validate(self) -> bool:
        """验证配置参数的有效性"""
        try:
            # 验证采样率
            if self.sampling_rate <= 0:
                raise ValueError("采样率必须大于0")
            
            # 验证滤波参数
            if self.preprocessing["filtering"]["enabled"]:
                low_cutoff = self.preprocessing["filtering"]["low_cutoff"]
                high_cutoff = self.preprocessing["filtering"]["high_cutoff"]
                nyquist = self.sampling_rate / 2
                
                if low_cutoff >= high_cutoff:
                    raise ValueError("低截止频率必须小于高截止频率")
                
                if high_cutoff >= nyquist:
                    raise ValueError(f"高截止频率不能超过奈奎斯特频率 ({nyquist} Hz)")
            
            # 验证心率范围
            hr_range = self.peak_detection["heart_rate_range"]
            if hr_range[0] >= hr_range[1]:
                raise ValueError("心率范围设置无效")
            
            return True
            
        except Exception as e:
            print(f"配置验证失败: {e}")
            return False
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return asdict(self)
    
    @classmethod
    def from_dict(cls, config_dict: Union[Dict[str, Any], 'PipelineConfig']) -> 'PipelineConfig':
        """从字典或PipelineConfig对象创建配置对象"""
        if isinstance(config_dict, cls):
            # 如果已经是PipelineConfig对象，直接返回副本
            return config_dict.copy()
        elif isinstance(config_dict, dict):
            return cls(**config_dict)
        else:
            raise ValueError(f"config_dict必须是字典或PipelineConfig对象，得到: {type(config_dict)}")
    
    def copy(self) -> 'PipelineConfig':
        """创建配置副本"""
        return PipelineConfig(**self.to_dict())
    
    def update(self, updates: Dict[str, Any]) -> 'PipelineConfig':
        """更新配置参数"""
        config_dict = self.to_dict()
        
        def deep_update(base_dict, update_dict):
            for key, value in update_dict.items():
                if key in base_dict and isinstance(base_dict[key], dict) and isinstance(value, dict):
                    deep_update(base_dict[key], value)
                else:
                    base_dict[key] = value
        
        deep_update(config_dict, updates)
        return PipelineConfig.from_dict(config_dict)


def load_config(config_path: Union[str, Path]) -> PipelineConfig:
    """从文件加载配置
    
    支持JSON和YAML格式
    
    参数:
        config_path: 配置文件路径
        
    返回:
        PipelineConfig: 配置对象
    """
    config_path = Path(config_path)
    
    if not config_path.exists():
        raise FileNotFoundError(f"配置文件不存在: {config_path}")
    
    with open(config_path, 'r', encoding='utf-8') as f:
        if config_path.suffix.lower() in ['.yaml', '.yml']:
            if not YAML_AVAILABLE:
                raise ImportError("YAML支持需要安装pyyaml: pip install pyyaml")
            config_dict = yaml.safe_load(f)
        elif config_path.suffix.lower() == '.json':
            config_dict = json.load(f)
        else:
            raise ValueError(f"不支持的配置文件格式: {config_path.suffix}")
    
    config = PipelineConfig.from_dict(config_dict)
    
    if not config.validate():
        raise ValueError("配置文件验证失败")
    
    return config


def save_config(config: PipelineConfig, config_path: Union[str, Path], format: str = 'json') -> None:
    """保存配置到文件
    
    参数:
        config: 配置对象
        config_path: 保存路径
        format: 文件格式 ('yaml' 或 'json')
    """
    config_path = Path(config_path)
    config_path.parent.mkdir(parents=True, exist_ok=True)
    
    config_dict = config.to_dict()
    
    with open(config_path, 'w', encoding='utf-8') as f:
        if format.lower() in ['yaml', 'yml']:
            if not YAML_AVAILABLE:
                raise ImportError("YAML支持需要安装pyyaml: pip install pyyaml")
            yaml.dump(config_dict, f, default_flow_style=False, allow_unicode=True, indent=2)
        elif format.lower() == 'json':
            json.dump(config_dict, f, ensure_ascii=False, indent=2)
        else:
            raise ValueError(f"不支持的格式: {format}")


def create_config_template(config_path: Union[str, Path], pipeline_type: str = 'custom') -> None:
    """创建配置模板文件
    
    参数:
        config_path: 模板文件路径
        pipeline_type: Pipeline类型 ('custom' 或 'neurokit2')
    """
    from .default_configs import DEFAULT_CUSTOM_CONFIG, DEFAULT_NEUROKIT2_CONFIG
    
    if pipeline_type == 'custom':
        config = DEFAULT_CUSTOM_CONFIG
    elif pipeline_type == 'neurokit2':
        config = DEFAULT_NEUROKIT2_CONFIG
    else:
        raise ValueError(f"不支持的Pipeline类型: {pipeline_type}")
    
    save_config(config, config_path)